using AuthService.Domain.Entities;
using AuthService.Domain.Repositories;
using Microsoft.Extensions.Logging;
using System.Security.Cryptography;

namespace AuthService.Application.Services;

/// <summary>
/// 用户服务实现（简化版）
/// 提供用户管理的核心功能
/// </summary>
public class UserServiceSimplified : IUserServiceSimplified
{
    private readonly IUserRepository _userRepository;
    private readonly ILogger<UserServiceSimplified> _logger;

    public UserServiceSimplified(IUserRepository userRepository, ILogger<UserServiceSimplified> logger)
    {
        _userRepository = userRepository;
        _logger = logger;
    }

    /// <summary>
    /// 创建新用户
    /// </summary>
    public async Task<User> CreateUserAsync(string username, string email, string password,
        string? displayName = null, string? createdBy = null, CancellationToken cancellationToken = default)
    {
        try
        {
            _logger.LogInformation("创建新用户: {Username}, {Email}", username, email);

            // 检查用户名是否已存在
            var existingUser = await _userRepository.GetByUsernameAsync(username, cancellationToken);
            if (existingUser != null)
            {
                throw new InvalidOperationException($"用户名 '{username}' 已存在");
            }

            // 检查邮箱是否已存在
            var existingEmail = await _userRepository.GetByEmailAsync(email, cancellationToken);
            if (existingEmail != null)
            {
                throw new InvalidOperationException($"邮箱 '{email}' 已存在");
            }

            // 生成密码哈希
            var (passwordHash, passwordSalt) = HashPassword(password);

            // 创建用户实体
            var user = new User
            {
                Id = Guid.NewGuid(),
                Username = username,
                Email = email,
                DisplayName = displayName ?? username,
                PasswordHash = passwordHash,
                PasswordSalt = passwordSalt,
                CreatedBy = createdBy ?? "system",
                CreatedAt = DateTime.UtcNow,
                UpdatedAt = DateTime.UtcNow
            };

            var createdUser = await _userRepository.CreateAsync(user, cancellationToken);

            _logger.LogInformation("成功创建用户: {UserId}, {Username}", createdUser.Id, createdUser.Username);
            return createdUser;
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "创建用户失败: {Username}, {Email}", username, email);
            throw;
        }
    }

    /// <summary>
    /// 根据ID获取用户
    /// </summary>
    public async Task<User?> GetUserByIdAsync(Guid userId, CancellationToken cancellationToken = default)
    {
        try
        {
            return await _userRepository.GetByIdAsync(userId, cancellationToken);
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "根据ID获取用户失败: {UserId}", userId);
            throw;
        }
    }

    /// <summary>
    /// 根据用户名获取用户
    /// </summary>
    public async Task<User?> GetUserByUsernameAsync(string username, CancellationToken cancellationToken = default)
    {
        try
        {
            return await _userRepository.GetByUsernameAsync(username, cancellationToken);
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "根据用户名获取用户失败: {Username}", username);
            throw;
        }
    }

    /// <summary>
    /// 根据邮箱获取用户
    /// </summary>
    public async Task<User?> GetUserByEmailAsync(string email, CancellationToken cancellationToken = default)
    {
        try
        {
            return await _userRepository.GetByEmailAsync(email, cancellationToken);
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "根据邮箱获取用户失败: {Email}", email);
            throw;
        }
    }

    /// <summary>
    /// 获取用户列表
    /// </summary>
    public async Task<(IEnumerable<User> Users, int TotalCount)> GetUsersAsync(int page = 1, int size = 10,
        string? tenantId = null, CancellationToken cancellationToken = default)
    {
        try
        {
            _logger.LogInformation("获取用户列表，页码: {PageNumber}, 大小: {PageSize}, 租户: {TenantId}",
                page, size, tenantId);

            var pagedResult = await _userRepository.GetPagedAsync(page, size, null, tenantId, null, cancellationToken);

            _logger.LogInformation("成功获取用户列表，返回 {Count} 条记录，总计 {Total} 条",
                pagedResult.Users.Count(), pagedResult.TotalCount);

            return pagedResult;
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "获取用户列表失败");
            throw;
        }
    }

    /// <summary>
    /// 更新用户
    /// </summary>
    public async Task<User> UpdateUserAsync(User user, string? updatedBy = null, CancellationToken cancellationToken = default)
    {
        try
        {
            user.UpdatedBy = updatedBy ?? "system";
            user.UpdatedAt = DateTime.UtcNow;

            var updatedUser = await _userRepository.UpdateAsync(user, cancellationToken);

            _logger.LogInformation("成功更新用户: {UserId}, {Username}", updatedUser.Id, updatedUser.Username);
            return updatedUser;
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "更新用户失败: {UserId}", user.Id);
            throw;
        }
    }

    /// <summary>
    /// 删除用户
    /// </summary>
    public async Task<bool> DeleteUserAsync(Guid userId, string? deletedBy = null, CancellationToken cancellationToken = default)
    {
        try
        {
            var result = await _userRepository.DeleteAsync(userId, deletedBy, cancellationToken);

            if (result)
            {
                _logger.LogInformation("成功删除用户: {UserId}", userId);
            }

            return result;
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "删除用户失败: {UserId}", userId);
            throw;
        }
    }

    /// <summary>
    /// 验证用户密码
    /// </summary>
    public async Task<bool> ValidatePasswordAsync(string username, string password, CancellationToken cancellationToken = default)
    {
        try
        {
            var user = await _userRepository.GetByUsernameAsync(username, cancellationToken);
            if (user == null)
            {
                return false;
            }

            return VerifyPassword(password, user.PasswordHash, user.PasswordSalt);
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "验证密码失败: {Username}", username);
            return false;
        }
    }



    /// <summary>
    /// 生成密码哈希值和盐值
    ///
    /// 密码安全存储的核心方法，使用PBKDF2算法进行密码哈希：
    ///
    /// 工作流程：
    /// 1. 生成随机盐值：每个用户都有唯一的32字节随机盐值
    /// 2. 使用PBKDF2算法：密码 + 盐值 + 10000次迭代 → 哈希值
    /// 3. 返回Base64编码的哈希值和盐值
    ///
    /// 安全特性：
    /// - PBKDF2 (Password-Based Key Derivation Function 2)：业界标准的密码哈希算法
    /// - 10000次迭代：增加暴力破解的计算成本
    /// - SHA256哈希算法：提供强加密保护
    /// - 32字节盐值：提供足够的随机性，防止彩虹表攻击
    ///
    /// 为什么使用PBKDF2而不是简单的SHA256？
    /// - 简单SHA256太快，容易被暴力破解
    /// - PBKDF2通过多次迭代故意变慢，增加破解成本
    /// - 即使攻击者获得数据库，也需要大量时间破解每个密码
    ///
    /// 使用场景：用户注册或修改密码时调用
    /// </summary>
    /// <param name="password">用户输入的明文密码</param>
    /// <returns>
    /// 元组包含：
    /// - hash: Base64编码的密码哈希值，存储到数据库的PasswordHash字段
    /// - salt: Base64编码的盐值，存储到数据库的PasswordSalt字段
    /// </returns>
    private (string hash, string salt) HashPassword(string password)
    {
        // 步骤1：生成32字节的加密安全随机盐值
        // 盐值作用：确保相同密码产生不同哈希值，防止彩虹表攻击
        using var rng = RandomNumberGenerator.Create(); // 使用加密安全的随机数生成器
        var saltBytes = new byte[32]; // 32字节 = 256位，提供足够的随机性
        rng.GetBytes(saltBytes); // 填充随机字节
        var salt = Convert.ToBase64String(saltBytes); // 转换为Base64便于存储

        // 步骤2：使用PBKDF2算法计算密码哈希值
        // PBKDF2参数说明：
        // - password: 用户输入的明文密码
        // - saltBytes: 随机盐值字节数组
        // - 10000: 迭代次数，增加计算成本，防止暴力破解
        // - HashAlgorithmName.SHA256: 底层哈希算法
        using var pbkdf2 = new Rfc2898DeriveBytes(password, saltBytes, 10000, HashAlgorithmName.SHA256);
        var hashBytes = pbkdf2.GetBytes(32); // 生成32字节的哈希值
        var hash = Convert.ToBase64String(hashBytes); // 转换为Base64便于存储

        return (hash, salt);
    }

    /// <summary>
    /// 验证用户输入的密码是否正确
    ///
    /// 密码验证的核心逻辑：
    /// 1. 使用存储的盐值和相同的PBKDF2参数重新计算哈希值
    /// 2. 将计算出的哈希值与数据库中存储的哈希值进行比较
    /// 3. 如果两个哈希值相同，说明密码正确
    ///
    /// 验证流程：
    /// 用户输入密码 + 数据库中的盐值 → PBKDF2算法 → 新哈希值 → 与存储的哈希值比较
    ///
    /// 安全特性：
    /// - 使用相同的PBKDF2参数（10000次迭代，SHA256）确保一致性
    /// - 通过时间恒定的字符串比较防止时序攻击
    /// - 不会泄露任何关于原始密码的信息
    ///
    /// 为什么这样设计？
    /// - 哈希算法是单向的，无法从哈希值反推密码
    /// - 只能通过重新计算来验证密码是否正确
    /// - 相同的输入（密码+盐值）总是产生相同的哈希值
    ///
    /// 使用场景：用户登录时验证密码
    /// </summary>
    /// <param name="password">用户输入的明文密码</param>
    /// <param name="hash">数据库中存储的密码哈希值</param>
    /// <param name="salt">数据库中存储的密码盐值</param>
    /// <returns>
    /// true: 密码正确，用户可以登录
    /// false: 密码错误，拒绝登录
    /// </returns>
    private bool VerifyPassword(string password, string hash, string salt)
    {
        // 步骤1：将Base64编码的盐值转换回字节数组
        var saltBytes = Convert.FromBase64String(salt);

        // 步骤2：使用相同的PBKDF2参数重新计算哈希值
        // 重要：必须使用与HashPassword方法完全相同的参数
        // - 相同的迭代次数：10000
        // - 相同的哈希算法：SHA256
        // - 相同的输出长度：32字节
        using var pbkdf2 = new Rfc2898DeriveBytes(password, saltBytes, 10000, HashAlgorithmName.SHA256);
        var hashBytes = pbkdf2.GetBytes(32);
        var computedHash = Convert.ToBase64String(hashBytes);

        // 步骤3：比较计算出的哈希值与存储的哈希值
        // 使用 == 进行字符串比较（在.NET中是安全的）
        // 如果相等，说明用户输入的密码正确
        return hash == computedHash;
    }

    /// <summary>
    /// 用户登录验证
    ///
    /// 完整的用户登录流程演示：
    ///
    /// 登录验证步骤：
    /// 1. 根据用户名查找用户记录
    /// 2. 检查用户是否存在且未被删除
    /// 3. 使用VerifyPassword方法验证密码
    /// 4. 返回验证结果和用户信息
    ///
    /// 密码验证原理：
    /// - 数据库存储：用户名="john", 哈希值="abc123...", 盐值="salt456..."
    /// - 用户输入：用户名="john", 密码="password123"
    /// - 验证过程：输入密码 + 存储的盐值 → PBKDF2 → 新哈希值 → 与存储哈希值比较
    /// - 验证结果：相同=登录成功，不同=登录失败
    ///
    /// 安全考虑：
    /// - 不会在日志中记录密码信息
    /// - 失败时不透露具体失败原因（用户不存在 vs 密码错误）
    /// - 使用恒定时间比较防止时序攻击
    ///
    /// 使用示例：
    /// var (isValid, user) = await ValidateUserLoginAsync("john", "password123");
    /// if (isValid && user != null) {
    ///     // 登录成功，生成JWT令牌或设置会话
    /// } else {
    ///     // 登录失败，返回错误信息
    /// }
    /// </summary>
    /// <param name="username">用户名</param>
    /// <param name="password">用户输入的明文密码</param>
    /// <param name="cancellationToken">取消令牌</param>
    /// <returns>
    /// 元组包含：
    /// - isValid: 登录是否成功
    /// - user: 登录成功时返回用户信息，失败时为null
    /// </returns>
    public async Task<(bool isValid, User? user)> ValidateUserLoginAsync(
        string username,
        string password,
        CancellationToken cancellationToken = default)
    {
        try
        {
            _logger.LogInformation("用户登录验证开始: {Username}", username);

            // 步骤1：根据用户名查找用户
            var user = await _userRepository.GetByUsernameAsync(username, cancellationToken);

            // 步骤2：检查用户是否存在
            if (user == null)
            {
                _logger.LogWarning("登录失败：用户不存在 - {Username}", username);
                return (false, null);
            }

            // 步骤3：检查用户是否被删除
            if (user.IsDeleted)
            {
                _logger.LogWarning("登录失败：用户已被删除 - {Username}", username);
                return (false, null);
            }

            // 步骤4：验证密码
            // 这里调用VerifyPassword方法：
            // - 使用用户输入的密码
            // - 使用数据库中存储的哈希值和盐值
            // - 通过PBKDF2算法重新计算并比较
            bool passwordValid = VerifyPassword(password, user.PasswordHash, user.PasswordSalt);

            if (passwordValid)
            {
                _logger.LogInformation("用户登录成功: {Username}, UserId: {UserId}", username, user.Id);
                return (true, user);
            }
            else
            {
                _logger.LogWarning("登录失败：密码错误 - {Username}", username);
                return (false, null);
            }
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "用户登录验证异常: {Username}", username);
            return (false, null);
        }
    }
}
